Package com.bric.plaf

Source Code of com.bric.plaf.FocusArrowListener

/*
* @(#)FocusArrowListener.java
*
* $Date: 2011-05-02 16:01:45 -0500 (Mon, 02 May 2011) $
*
* Copyright (c) 2011 by Jeremy Wood.
* All rights reserved.
*
* The copyright of this software is owned by Jeremy Wood.
* You may not use, copy or modify this software, except in 
* accordance with the license agreement you entered into with 
* Jeremy Wood. For details see accompanying license terms.
*
* This software is probably, but not necessarily, discussed here:
* http://javagraphics.java.net/
*
* That site should also contain the most recent official version
* of this software.  (See the SVN repository for more details.)
*/
package com.bric.plaf;

import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/** This listens for arrow keys and shifts
* the keyboard focus accordingly.
* So if you press the left arrow key, the component
* to the left of the source component requests the focus.
* <P>This scans for the first available component whose
* <code>isFocusable()</code> method returns <code>true</code>.
* If no such component is found: nothing happens.
*/
public class FocusArrowListener extends KeyAdapter {

  public void keyPressed(KeyEvent e) {
    int code = e.getKeyCode();
    int dx = 0;
    int dy = 0;
    if(code==KeyEvent.VK_LEFT) {
      dx = -1;
    } else if(code==KeyEvent.VK_UP) {
      dy = -1;
    } else if(code==KeyEvent.VK_RIGHT) {
      dx = 1;
    } else if(code==KeyEvent.VK_DOWN) {
      dy = 1;
    }

    if( (dx==0 && dy==0)==false && shiftFocus(dx,dy,(Component)e.getSource()))
      e.consume();
  }
 
  /** Shifts the focus in a certain direction.
   *
   * @param dx the amount to increment x.
   * @param dy the amount to increment y.
   * @param src the source to traverse from.
   * @return true if another component requested the focus
   * as a result of this method.  This may return false if
   * no suitable component was found to shift focus to.
   * (If you press the right arrow key on the right-most
   * component, for example.)
   */
  public static boolean shiftFocus(int dx,int dy,Component src) {
    if(dx==0 && dy==0) //this would result in an infinite loop
      throw new IllegalArgumentException("dx ("+dx+") and ("+dy+") cannot both be zero");
   
    Set focusableComponents = getFocusableComponents(src);
   
    int x = src.getWidth()/2;
    int y = src.getHeight()/2;
    Window window = SwingUtilities.getWindowAncestor(src);
    if(window==null) return false;
    Point p = SwingUtilities.convertPoint(src, x, y, window);
   
    Component comp = null;
    int windowWidth = window.getWidth();
    int windowHeight = window.getHeight();
   
    while(p.x>0 && p.x<windowWidth && p.y>0 && p.y<windowHeight && (comp==null || comp==src || (comp instanceof JPanel))) {
      p.x += dx;
      p.y += dy;
      comp = SwingUtilities.getDeepestComponentAt(window, p.x, p.y);
      boolean canAcceptFocus = focusableComponents.contains( comp );
      if(comp!=null && canAcceptFocus==false)
        comp = null;
    }
   
    //TODO: implement a more robust searching mechanism instead of the above
    //If a component is below the src, but to the left or right of the center:
    //it should still be detected when you press the down arrow key.

    if(comp!=null && comp!=src && comp!=window && (!(comp instanceof JPanel))) {
      comp.requestFocus();
      return true;
    }
    return false;
  }
 
  /** Returns a set of all the components that
   * can have the keyboard focus.
   * <P>My first implementation involved of this concept
   * simply involved asking JCompnonents if they were
   * focusable, but in the <code>FilledButtonTest</code> this
   * resulted in shifting focus to the ContentPane.  Although
   * it is technically focusable: if I used the tab key
   * I did <i>not</i> get this result.  So I studied
   * the inner workings for Component.transferFocus()
   * and ended up with a method that involved
   * calls to <code>getFocusCycleRootAncestor()</code>,
   * and <code>getFocusTraversalPolicy()</code>.
   * <P>(Also credit goes to Werner for originally tipping me off
   * towards looking at FocusTraversalPolicies.)
   * @param currentFocusOwner the current focus owner.
   * @return all the JComponents that can receive the focus.
   */
  public static Set getFocusableComponents(Component currentFocusOwner) {
    HashSet set = new HashSet();
    set.add(currentFocusOwner);

        Container rootAncestor = currentFocusOwner.getFocusCycleRootAncestor();
        Component comp = currentFocusOwner;
        while (rootAncestor != null &&
               !(rootAncestor.isShowing() &&
                 rootAncestor.isFocusable() &&
                 rootAncestor.isEnabled()))
        {
            comp = rootAncestor;
            rootAncestor = comp.getFocusCycleRootAncestor();
        }
        if (rootAncestor != null) {
            FocusTraversalPolicy policy =
                rootAncestor.getFocusTraversalPolicy();
            Component toFocus = policy.getComponentAfter(rootAncestor, comp);
            final Component startingPoint = currentFocusOwner;
           
            while(toFocus!=null && set.contains(toFocus)==false) {
              set.add(toFocus);
                toFocus = policy.getComponentAfter(rootAncestor, toFocus);
            }
           
            toFocus = policy.getComponentBefore(rootAncestor, comp);
           
            while(toFocus!=null && set.contains(toFocus)==false) {
              set.add(toFocus);
                toFocus = policy.getComponentBefore(rootAncestor, toFocus);
            }
        }
    return set;
  }
}
TOP

Related Classes of com.bric.plaf.FocusArrowListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.